luci-mod-status: add support to show/hide index cards
authorChristian Marangi <[email protected]>
Tue, 21 Nov 2023 20:54:10 +0000 (21:54 +0100)
committerPaul Donald <[email protected]>
Thu, 2 Oct 2025 13:11:51 +0000 (15:11 +0200)
Add support to show/hide index cards. A card's state is saved using the
browser localstorage and its state is restored on page reload/relogin.

Rework the pool function to check and skip loading of hidden cards.

Rework themes to address new button position.

Signed-off-by: Christian Marangi <[email protected]>
[ changed tabs in CSS ]
Signed-off-by: Paul Donald <[email protected]>
modules/luci-mod-status/htdocs/luci-static/resources/view/status/index.js
themes/luci-theme-bootstrap/htdocs/luci-static/bootstrap/cascade.css
themes/luci-theme-material/htdocs/luci-static/material/cascade.css
themes/luci-theme-openwrt-2020/htdocs/luci-static/openwrt2020/cascade.css
themes/luci-theme-openwrt/htdocs/luci-static/openwrt.org/cascade.css

index a232f315c01255d051777329105e5266e0819e0e..243f66daa4f4e8b20a836a2b14b26ccced4a0605 100644 (file)
@@ -4,12 +4,42 @@
 'require poll';
 'require fs';
 'require network';
+'require ui';
 
 return view.extend({
-       invokeIncludesLoad: function(includes) {
+       handleToggleSection: function(include, container, ev) {
+               var btn = ev.currentTarget;
+
+               include.hide = !include.hide;
+
+               btn.setAttribute('data-style', include.hide ? 'active' : 'inactive');
+               btn.firstChild.data = include.hide ? _('Show') : _('Hide');
+               btn.blur();
+
+               container.style.display = include.hide ? 'none' : 'block';
+
+               if (include.hide) {
+                       localStorage.setItem(include.id, 'hide');
+               } else {
+                       dom.content(container,
+                               E('p', {}, E('em', { 'class': 'spinning' },
+                                       [ _('Collecting data...') ])
+                               )
+                       );
+
+                       localStorage.removeItem(include.id);
+               }
+       },
+
+       invokeIncludesLoad: function(includes, first_load) {
                var tasks = [], has_load = false;
 
                for (var i = 0; i < includes.length; i++) {
+                       if (includes[i].hide && !first_load) {
+                               tasks.push(null);
+                               continue;
+                       }
+
                        if (typeof(includes[i].load) == 'function') {
                                tasks.push(includes[i].load().catch(L.bind(function() {
                                        this.failed = true;
@@ -25,13 +55,16 @@ return view.extend({
                return has_load ? Promise.all(tasks) : Promise.resolve(null);
        },
 
-       poll_status: function(includes, containers) {
+       poll_status: function(includes, containers, first_load) {
                return network.flushCache().then(L.bind(
-                       this.invokeIncludesLoad, this, includes
+                       this.invokeIncludesLoad, this, includes, first_load
                )).then(function(results) {
                        for (var i = 0; i < includes.length; i++) {
                                var content = null;
 
+                               if (includes[i].hide && !first_load)
+                                       continue;
+
                                if (includes[i].failed)
                                        continue;
 
@@ -49,7 +82,8 @@ return view.extend({
                                        containers[i].parentNode.style.display = '';
                                        containers[i].parentNode.classList.add('fade-in');
 
-                                       dom.content(containers[i], content);
+                                       if (!includes[i].hide)
+                                               dom.content(containers[i], content);
                                }
                        }
 
@@ -87,19 +121,33 @@ return view.extend({
                                                function(m, s, c) { return (s ? ' ' : '') + c.toUpperCase() })
                                        });
 
+                       includes[i].id = title;
+                       includes[i].hide = localStorage.getItem(includes[i].id) == 'hide';
+
                        var container = E('div');
 
-                       rv.appendChild(E('div', { 'class': 'cbi-section', 'style': 'display:none' }, [
-                               title != '' ? E('h3', title) : '',
+                       rv.appendChild(E('div', { 'class': 'cbi-section', 'style': 'display: none' }, [
+                               E('div', { 'class': 'cbi-title' },[
+                                       title != '' ? E('h3', title) : '',
+                                       E('div', [
+                                               E('span', {
+                                                       'data-style': includes[i].hide ? 'active' : 'inactive',
+                                                       'data-indicator': 'poll-status',
+                                                       'data-clickable': 'true',
+                                                       'click': ui.createHandlerFn(this, 'handleToggleSection',
+                                                                                   includes[i], container)
+                                               }, [ _(includes[i].hide ? 'Show' : 'Hide') ])
+                                       ]),
+                               ]),
                                container
                        ]));
 
                        containers.push(container);
                }
 
-               return this.poll_status(includes, containers).then(function() {
+               return this.poll_status(includes, containers, true).then(L.bind(function() {
                        return poll.add(L.bind(this.poll_status, this, includes, containers))
-               }).then(function() {
+               }, this)).then(function() {
                        return rv;
                });
        },
index 6ab19035cea5c7fdf03de89601a00acb324d3037..c1be937697f9accde02e26a74a06d614b4fd26ea 100644 (file)
@@ -2014,6 +2014,38 @@ form.inline { display: inline; margin-bottom: 0; }
        font-family: monospace;
 }
 
+.cbi-title {
+       display: flex;
+}
+
+.cbi-title div {
+       margin-left: 5px;
+       margin-right: auto;
+       align-self: center;
+}
+
+.cbi-title [data-indicator] {
+       padding: 3px 3px 2px;
+       font-size: 9.75px;
+       font-weight: bold;
+       color: var(--text-color-high);
+       text-transform: uppercase;
+       white-space: nowrap;
+       background-color: var(--background-color-low);
+       border-radius: 3px;
+       text-shadow: none;
+       margin: .125em 0 .125em .4em;
+}
+
+.cbi-title [data-indicator][data-style="active"] {
+       color: var(--on-primary-color);
+       background-color: var(--primary-color-high);
+}
+
+.cbi-title [data-indicator][data-clickable] {
+       cursor: pointer;
+}
+
 .cbi-section-table .tr:hover .td,
 .cbi-section-table .tr:hover .th,
 .cbi-section-table .tr:hover::before {
index 338d7b4fb39c880bd29a12b00db8f55a3f18ec65..8e491e10c95e4f7bf6c2458c4a92bb90ea6b2cf9 100644 (file)
@@ -807,6 +807,7 @@ fieldset > fieldset,
 }
 
 .cbi-section > h3:first-child,
+.cbi-title,
 .panel-title {
        font-size: 1.4rem;
        line-height: 1;
@@ -819,6 +820,28 @@ fieldset > fieldset,
        border-bottom: thin solid #eee;
 }
 
+.cbi-title {
+       display: flex;
+}
+
+.cbi-title > h3:first-child {
+       font-size: unset;
+       margin: unset;
+       padding-bottom: unset;
+}
+
+.cbi-title [data-indicator] {
+       position: relative;
+       top: 0.2rem;
+       float: left;
+       margin-left: 0.3rem;
+       cursor: pointer;
+}
+
+.cbi-title [data-indicator][data-style="active"] {
+       background-color: #002B49 !important;
+}
+
 .cbi-section > h4:first-child,
 .cbi-section > p:first-child,
 [data-tab-title] > h3:first-child,
index cd8fef6a2741e6dc53c8f8c72dc1eccb179ab29e..ec89ba5df92ba18e4e733413dfcf0d913c415931 100644 (file)
@@ -369,6 +369,44 @@ tr.placeholder > td {
  * view specific table invariants
  */
 
+.cbi-title {
+       display: flex;
+        margin: 0 0 1rem 0;
+}
+
+.cbi-title > h3{
+       margin: unset;
+}
+
+.cbi-title div {
+       margin-left: 5px;
+       margin-right: auto;
+       align-self: center;
+}
+
+.cbi-title [data-indicator] {
+       background: var(--secondary-bright-color);
+       color: var(--main-bright-color);
+       border: 0.5px solid var(--main-bright-color);
+       display: inline-block;
+       font-size: .85em;
+       line-height: calc(1.5em - 1px);
+       padding: 0 calc(0.5em - 0.5px);
+       margin: 0.125em;
+       border-radius: 1em;
+       white-space: nowrap;
+}
+
+.cbi-title [data-indicator][data-style="active"] {
+       background: var(--main-bright-color);
+       color: var(--secondary-bright-color);
+       border: 0.5px solid var(--secondary-bright-color);
+}
+
+.cbi-title [data-indicator][data-clickable] {
+       cursor: pointer;
+}
+
  #cbi-wireless-wifi-device .ifacebadge {
        flex-direction: column;
        justify-content: space-around;
index 34896af979d4ec30f8acc74a5f77b057058d6ba6..224c282773f5a0e8f0aef2dadfaade7704f7c150 100644 (file)
@@ -565,6 +565,48 @@ p {
        display: none;
 }
 
+.cbi-title {
+       display: flex;
+       border-bottom: 1px solid;
+       padding-bottom: 4px;
+       margin: .25em 0 .5em 0;
+}
+
+.cbi-title > h3 {
+       border-bottom: unset;
+       padding-bottom: unset;
+       margin: unset;
+       width: unset;
+}
+
+
+.cbi-title div {
+       margin-left: 5px;
+       margin-right: auto;
+       align-self: center;
+}
+
+.cbi-title [data-indicator] {
+       text-transform: uppercase;
+       background: #90c0e0 !important;
+       color: #000 !important;
+       font-size: 11px;
+       padding: 0.125em 0.5em;
+       margin: 0.125em;
+       border-radius: 0.6em;
+}
+
+.cbi-title [data-indicator][data-style="inactive"] {
+       border: 1px solid #90c0e0;
+       background: #fff !important;
+       color: #90c0e0 !important;
+       padding: calc(.125em-1px) calc(.5em-1px);
+}
+
+.cbi-title [data-indicator][data-clickable] {
+       cursor: pointer;
+}
+
 .cbi-title-ref {
        color: #37c;
 }